package com.sdleyou.treepro.common.service.impl;

import com.sdleyou.treepro.common.exception.ServiceException;
import com.sdleyou.treepro.common.model.convert.UserTreePlantDO2UserTreePlantVO;
import com.sdleyou.treepro.common.model.dao.*;
import com.sdleyou.treepro.common.model.dto.ExchangeDTO;
import com.sdleyou.treepro.common.model.dto.WellDTO;
import com.sdleyou.treepro.common.model.enums.ErrorCodeEnum;
import com.sdleyou.treepro.common.model.utils.RandomUtil;
import com.sdleyou.treepro.common.model.vo.*;
import com.sdleyou.treepro.common.rabbitmq.AmqpExchange;
import com.sdleyou.treepro.common.rabbitmq.message.TreeChangeMsg;
import com.sdleyou.treepro.common.service.*;
import com.sdleyou.treepro.common.utils.DateUtil;
import com.sdleyou.treepro.common.utils.IdGen;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.amqp.core.AmqpTemplate;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Sort;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.Date;

import org.springframework.data.mongodb.core.query.Update;
import org.springframework.util.StringUtils;

import java.math.BigDecimal;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Service
public class UserTreeManagerImpl implements UserTreeManager {

    @Autowired
    private MongoTemplate mongoTemplate;
    @Autowired
    private TreeManager treeManager;
    @Autowired
    private UserManager userManager;
    @Autowired
    private UserPropManager userPropManager;
    @Autowired
    private UserMessageManager userMessageManager;
    @Autowired
    private UserAchievementManager userAchievementManager;
    @Autowired
    private AmqpTemplate amqpTemplate;
    @Autowired
    private LastRequestTimeManager lastRequestTimeManager;

    private Logger logger = LoggerFactory.getLogger(this.getClass());

    /**
     * 树木类型列表
     *
     * @return
     */
    @Override
    public UserTreeVO getTreeTypeList() {
        return null;
    }

    /**
     * 用户选择种树类型
     */
    @Override
    public Map<String, String> userPlant(String userId, String treeType) {
        UserTreeDO userTreeDO = new UserTreeDO();
        UserVO userVO = userManager.userInfo(userId);
        if (userVO == null) {
            throw new ServiceException(ErrorCodeEnum.E100.code(), "用户不存在");
        }
        //获取树类型信息
        TreeVO treeVO = treeManager.findOne(treeType);
        userTreeDO.setTreeId(IdGen.uuid());
        userTreeDO.setTreeName(treeVO.getTreeName());
        userTreeDO.setTreeDesc(treeVO.getTreeDesc());
        userTreeDO.setTreeIcon(treeVO.getTreeIcon());
        userTreeDO.setTreeImage(treeVO.getTreeImage());
        userTreeDO.setGrowValue(treeVO.getGrowValue());

        userTreeDO.setTreeType(treeType);
        userTreeDO.setIsShow("HIDDEN");
        userTreeDO.setCurrentValue(0.0);
        userTreeDO.setUserId(userId);
        userTreeDO.setNickname(userVO.getNickname());
        userTreeDO.setFace(userVO.getFace());
        userTreeDO.setCreatedAt(DateUtil.getDateline());
        userTreeDO.setFinishedAt(0L);
        userTreeDO.setPlantType("PERSON");
        userTreeDO.setTreeStatus(0);
        userTreeDO.setGmtCreate(DateUtil.getDateline());
        userTreeDO.setGmtModified(DateUtil.getDateline());
        mongoTemplate.insert(userTreeDO);

        userManager.upDateAfterChooseTree(userId, userTreeDO.getTreeId());

        return null;
    }

    /**
     * 用户获取树木信息
     */
    @Override
    public UserTreeVO getTreeInfoById(String userId, String treeId) {
        Query query = new Query(Criteria.where("user_id").is(userId).and("tree_id").is(treeId));
        UserTreeDO userTreeDO = mongoTemplate.findOne(query, UserTreeDO.class);
        UserTreeVO userTreeVO = new UserTreeVO();
        if (userTreeDO == null) {
            throw new ServiceException(ErrorCodeEnum.E300.code(), "暂无树木信息");
        }
        BeanUtils.copyProperties(userTreeDO, userTreeVO);
        //设置虫子减少的成长值
        if (userTreeVO.getSubValue() == null) {
            Integer subValue = setSubValue(userId, treeId);
            userTreeVO.setSubValue(subValue);
        }
        //是否树木是否养成 养成返回rewardValue 否则返回null
        BigDecimal total = new BigDecimal(userTreeDO.getGrowValue());
        BigDecimal current = new BigDecimal(userTreeDO.getCurrentValue());
        if (current.compareTo(total) < 0) {
            userTreeVO.setRewardValue(null);
        }
        userTreeVO.setValue(userTreeDO.getRewardValue());
        //计算树与图片的比例
        Integer growValue = userTreeDO.getGrowValue();
        Double currentValue = userTreeDO.getCurrentValue();
        Double[] treeImgProportion = treeManager.getTreeImgProportion();
        double currentProp = currentValue / growValue;//当前的比例
        int pos = 0;
        for (Double levelProp : treeImgProportion) {
            BigDecimal c = new BigDecimal(currentProp);
            BigDecimal l = new BigDecimal(levelProp);
            if (c.compareTo(l) >= 0) {
                pos++;
            } else {
                break;
            }
        }
        userTreeVO.setStage(pos + 1);
        if (pos == 0) {
            userTreeVO.setStageMin(0);
            userTreeVO.setStageMax((int) (growValue * treeImgProportion[pos]));
        } else if (pos == 5) {
            userTreeVO.setStageMin((int) (growValue * treeImgProportion[pos - 1]));
            userTreeVO.setStageMax(growValue);
        } else {
            userTreeVO.setStageMin((int) (growValue * treeImgProportion[pos - 1]));
            userTreeVO.setStageMax((int) (growValue * treeImgProportion[pos]));
        }
        userTreeVO.setTreeImage(userTreeDO.getTreeImage().get(pos));
        userTreeVO.setCurrentStageValue(userTreeVO.getCurrentValue() - userTreeVO.getStageMin());
        return userTreeVO;
    }

    /**
     * 计算减少成长值
     */
    @Override
    public Integer setSubValue(String userId, String treeId) {
        //计算减少的成长值
        Query query = new Query(Criteria.where("user_id").is(userId).and("tree_id").is(treeId));
        UserTreeDO userTreeDO = mongoTemplate.findOne(query, UserTreeDO.class);
        if (userTreeDO != null) {
            Integer wormNum = userTreeDO.getWormNum();
            if (wormNum != 0) {
                //获取上次的时间
                Long lastRequestTime = userTreeDO.getFirstWormTime();
                //System.out.println("lastRequestTime = " + lastRequestTime);
                if (lastRequestTime != null) {
                    Integer minTime = DateUtil.getMin(DateUtil.toString(lastRequestTime, "yyyy-MM-dd HH:mm:ss"));
                    //System.out.println("minTime = " + minTime);
                    if (minTime >= 60) {
                        minTime -= 60;
                        int times = minTime / 30;
                        Integer sub = calculateSubValue(wormNum, times);
                        //设置减少的值
                        Update update = new Update();
                        update.set("sub_value", sub);
                        mongoTemplate.updateFirst(query, update, UserTreeDO.class);
                        return sub;
                    }
                }
            }
        }
        return null;
    }

    /**
     * 计算减少多少成长值
     *
     * @param wormNum
     * @param times
     * @return
     */
    private Integer calculateSubValue(int wormNum, int times) {
        int sub = 0;
        if (wormNum == 1) {
            sub = 5;
        } else if (wormNum == 2) {
            sub = 8;
        } else if (wormNum == 3) {
            sub = 10;
        }
        return sub * times;
    }

    /**
     * 增加成长值
     */
    @Override
    public Map<String, String> addValue(String userId, String treeId, Double value) {
        Query query = new Query(Criteria.where("tree_id").is(treeId));
        UserTreeDO userTreeDO = mongoTemplate.findOne(query, UserTreeDO.class);
        if (userTreeDO == null) {
            throw new ServiceException(ErrorCodeEnum.E300.code(), "暂无树木信息");
        }
        Update update = new Update();
        Integer growValue = userTreeDO.getGrowValue();

        BigDecimal a = new BigDecimal(String.valueOf(value));
        BigDecimal b = new BigDecimal(String.valueOf(userTreeDO.getCurrentValue()));
        BigDecimal c = a.add(b);
        BigDecimal d = new BigDecimal(String.valueOf(growValue));
        if (c.compareTo(d) >= 0) {
            //该树已养成
            update.set("current_value", d.doubleValue());
            update.set("finished_at", DateUtil.getDateline());
            update.set("tree_status", 1);
            update.set("gmt_modified", DateUtil.getDateline());
            mongoTemplate.updateFirst(query, update, UserTreeDO.class);
            //更新用户属性
            userManager.upDateAfterFinishPlant(userId);
        } else {
            //未养成，增加树的成长值
            update.set("current_value", c.doubleValue());
            update.set("gmt_modified", DateUtil.getDateline());
            mongoTemplate.updateFirst(query, update, UserTreeDO.class);
        }
        return null;
    }

    /**
     * 减少成长值
     *
     * @param userId
     * @param treeId
     * @return
     */
    @Override
    public Map<String, String> subValue(String userId, String treeId) {
        Query query = new Query(Criteria.where("tree_id").is(treeId));
        UserTreeDO userTreeDO = mongoTemplate.findOne(query, UserTreeDO.class);
        if (userTreeDO == null) {
            throw new ServiceException(ErrorCodeEnum.E300.code(), "暂无树木信息");
        }
        if (userTreeDO.getSubValue() == null) {
            throw new ServiceException(ErrorCodeEnum.E303.code(), "无需减少");
        }
        Update update = new Update();

        BigDecimal a = new BigDecimal(String.valueOf(userTreeDO.getSubValue()));
        BigDecimal b = new BigDecimal(String.valueOf(userTreeDO.getCurrentValue()));
        BigDecimal c = b.subtract(a);
        BigDecimal d = new BigDecimal(0);
        if (d.compareTo(c) >= 0) {
            update.set("current_value", 0D);
        } else {
            update.set("current_value", c.doubleValue());
        }
        update.set("gmt_modified", DateUtil.getDateline());
        mongoTemplate.updateFirst(query, update, UserTreeDO.class);
        return null;
    }

    /**
     * 更新树木养殖信息
     */
    @Override
    public Map<String, String> addTreePlantInfo(String userId, String treeId, String userPropId, String propId, String info) {
        //Query query = new Query(Criteria.where("tree_id").is(treeId));
        //UserTreePlantDO userTreePlantDO = mongoTemplate.findOne(query, UserTreePlantDO.class);
        UserTreePlantDO userTreePlantDO = new UserTreePlantDO();
        UserVO userVO = userManager.userInfo(userPropId);
        userTreePlantDO.setTreeId(treeId);
        userTreePlantDO.setUserId(userId);
        userTreePlantDO.setPropId(propId);
        userTreePlantDO.setUsedAt(DateUtil.getDateline());
        userTreePlantDO.setPropEffect(info);
        userTreePlantDO.setUsedUserId(userPropId);
        userTreePlantDO.setUsedUserName(userVO.getNickname());
        userTreePlantDO.setUsedUserFace(userVO.getFace());
        userTreePlantDO.setGmtCreate(DateUtil.getDateline());
        userTreePlantDO.setGmtModified(DateUtil.getDateline());
        if (userId.equals(userPropId)) {
            userTreePlantDO.setIsSelf(true);
        } else {
            userTreePlantDO.setIsSelf(false);
        }
        mongoTemplate.insert(userTreePlantDO);

        return null;
    }

    /**
     * 查看树木养殖信息
     */
    @Override
    public List<UserTreePlantVO> getTreePlantInfo(String userId, String treeId) {
        Query query = new Query(Criteria.where("tree_id").is(treeId));
        query.with(Sort.by(Sort.Order.desc("gmt_create")));
        List<UserTreePlantDO> userTreePlantDOS = mongoTemplate.find(query, UserTreePlantDO.class);
        if (userTreePlantDOS == null) {
            throw new ServiceException(ErrorCodeEnum.E300.code(), "暂无树木信息");
        }
        List<UserTreePlantVO> collect = userTreePlantDOS.stream().map(UserTreePlantDO2UserTreePlantVO::convert).collect(Collectors.toList());
        return collect;
    }

    /**
     * 生成用户树木关系记录
     *
     * @param wellDTO
     */
    @Override
    public void createUserTree(WellDTO wellDTO, String plantType) {
        Query query = new Query(Criteria.where("user_id").is(wellDTO.getUserId()));
        UserDO userDO = mongoTemplate.findOne(query, UserDO.class);
        if (userDO == null) {
            throw new ServiceException(ErrorCodeEnum.E100.code(), "用户不存在");
        }
        query = new Query(Criteria.where("tree_id").is(wellDTO.getTreeId()));
        TreeDO treeDO = mongoTemplate.findOne(query, TreeDO.class);
        if (treeDO == null) {
            throw new ServiceException(ErrorCodeEnum.E006.code(), "树木信息不存在");
        }
        UserTreeDO userTreeDO = new UserTreeDO();
        userTreeDO.setUserId(wellDTO.getUserId());
        userTreeDO.setFace(userDO.getFace());
        userTreeDO.setNickname(userDO.getNickname());
        userTreeDO.setTreeId(treeDO.getTreeId());
        userTreeDO.setTreeName(treeDO.getTreeName());
        userTreeDO.setTreeIcon(treeDO.getTreeIcon());
        userTreeDO.setTreeDesc(treeDO.getTreeDesc());
        userTreeDO.setTreeImage(treeDO.getTreeImage());
        userTreeDO.setGrowValue(treeDO.getGrowValue());
        userTreeDO.setCurrentValue(new Double(0));
        userTreeDO.setPlantType(plantType);
        userTreeDO.setTreeStatus(0);
        userTreeDO.setWormNum(0);
        userTreeDO.setWormTime(new Long(0));
        Date date = new Date();
        userTreeDO.setGmtCreate(date.getTime());
        userTreeDO.setGmtModified(date.getTime());
        mongoTemplate.insert(userTreeDO);
        return;
    }

    /**
     * 用户使用能量兑换树苗
     *
     * @param exchangeDTO
     */
    @Override
    public void exchangeTree(ExchangeDTO exchangeDTO) {
        Query queryUser = new Query(Criteria.where("user_id").is(exchangeDTO.getUserId()));
        UserDO userDO = mongoTemplate.findOne(queryUser, UserDO.class);
        if (userDO == null) {
            throw new ServiceException(ErrorCodeEnum.E100.code(), "用户不存在");
        }
        Query queryTree = new Query(Criteria.where("tree_id").is(exchangeDTO.getTreeId()));
        TreeDO treeDO = mongoTemplate.findOne(queryTree, TreeDO.class);
        if (treeDO == null) {
            throw new ServiceException(ErrorCodeEnum.E006.code(), "树木信息不存在");
        }
        if (userDO.getTotalValue() < treeDO.getPowerValue()) {
            throw new ServiceException(ErrorCodeEnum.E014.code(), "能量不足");
        }
        //找到未完成的坑位
        Query queryWell = new Query(Criteria.where("user_id").is(exchangeDTO.getUserId())
                .and("is_finish").is(false));
        WellDO wellDO = mongoTemplate.findOne(queryWell, WellDO.class);
        if (wellDO == null) {
            throw new ServiceException(ErrorCodeEnum.E015.code(), "没有待种植的坑位");
        }
        //只能选择坑位内预留的树苗信息
        if (wellDO.getPreTreeId() != null && !wellDO.getPreTreeId().equals(exchangeDTO.getTreeId())) {
            throw new ServiceException(ErrorCodeEnum.E022.code(), ErrorCodeEnum.E022.getDescription());
        }
        //扣除能量
        Integer value = (userDO.getTotalValue() - treeDO.getPowerValue()) > 0 ? userDO.getTotalValue() - treeDO.getPowerValue() : 0;
        Update updateUser = new Update();
        updateUser.set("total_value", value);
        updateUser.set("total_tree", (userDO.getTotalTree() == null ? 0 : userDO.getTotalTree()) + 1);
        updateUser.set("company_contribute", (userDO.getCompanyContribute() == null ? 0 : userDO.getCompanyContribute()) + 1);
        updateUser.set("tree_well", null);
        mongoTemplate.updateFirst(queryUser, updateUser, UserDO.class);
        //改变坑位信息
        Update updateWell = new Update();
        updateWell.set("status", "6");
        updateWell.set("is_finish", true);
        Date date = new Date();
        updateWell.set("finish_at", date.getTime());
        mongoTemplate.updateFirst(queryWell, updateWell, WellDO.class);
        //更新公司植树信息, 增加种植总数, 员工贡献, 树木统计
        if (!StringUtils.isEmpty(userDO.getCompanyId()) && exchangeDTO.getContribute()) {
            Query companyQuery = new Query(Criteria.where("company_id").is(userDO.getCompanyId()));
            CompanyDO companyDO = mongoTemplate.findOne(companyQuery, CompanyDO.class);
            if (companyDO != null) {
                List<CompanyTree> companyTrees = companyDO.getRecordTree();
                Update updateCompany = new Update();
                updateCompany.set("tree_count", companyDO.getTreeCount() + 1);
                updateCompany.set("record_tree", this.containTree(companyTrees, treeDO));
                mongoTemplate.updateFirst(companyQuery, updateCompany, CompanyDO.class);
            }
        }
        //记录广播消息通知全服
        BroadcastDO broadcastDO = new BroadcastDO();
        broadcastDO.setBroadId(RandomUtil.randomId());
        broadcastDO.setUserId(userDO.getUserId());
        broadcastDO.setUserName(userDO.getNickname());
        broadcastDO.setFace(userDO.getFace());
        broadcastDO.setContent("兑换了" + treeDO.getTreeName() + "树苗一株");
        broadcastDO.setGmtCreate(date.getTime());

        //异步记录全服广播
        this.amqpTemplate.convertAndSend(AmqpExchange.BROADCAST_MESSAGE, AmqpExchange.BROADCAST_MESSAGE + "_ROUTING", broadcastDO);

        //记录用户消息
        MessageVO messageVO = new MessageVO();
        messageVO.setType("SYSTEM");
        messageVO.setUserId(userDO.getUserId());
        messageVO.setContent("兑换了" + treeDO.getTreeName() + "树苗一株, 花费" + treeDO.getPowerValue() + "能量");
        userMessageManager.create(messageVO);

        //更新总植树量
        //userAchievementManager.updateTotalTree(1L);
        this.amqpTemplate.convertAndSend(AmqpExchange.TOTAL_TREE_CHANGE, AmqpExchange.TOTAL_TREE_CHANGE + "_ROUTING", new TreeChangeMsg(1L));

        return;
    }

    private List<CompanyTree> containTree(List<CompanyTree> companyTrees, TreeDO treeDO) {
        if (companyTrees != null && companyTrees.size() > 0) {
            for (int i = 0; i < companyTrees.size(); i++) {
                if (companyTrees.get(i).getTreeId().equals(treeDO.getTreeId())) {
                    companyTrees.get(i).setTotalCount(companyTrees.get(i).getTotalCount() + 1);
                    return companyTrees;
                }
            }
        } else {
            companyTrees = new ArrayList<>();
            CompanyTree companyTree = new CompanyTree();
            companyTree.setTotalCount(1);
            companyTree.setTreeId(treeDO.getTreeId());
            companyTree.setTreeName(treeDO.getTreeName());
            companyTree.setTreeIcon(treeDO.getTreeIcon());
            companyTree.setTreeImage(treeDO.getTreeImage());
            companyTrees.add(companyTree);
        }
        return companyTrees;
    }

    /**
     * 用户选择并生成游戏内的虚拟树苗
     *
     * @param userId
     * @param treeId
     */
    @Override
    public void initGameTree(String userId, String treeId) {
        Query query = new Query(Criteria.where("user_id").is(userId));
        UserDO userDO = mongoTemplate.findOne(query, UserDO.class);
        if (userDO == null) {
            throw new ServiceException(ErrorCodeEnum.E100.code(), "用户不存在");
        }
        if (userDO.getIsPlant()) {
            throw new ServiceException(ErrorCodeEnum.E301.code(), "已有正在养殖的树苗");
        }
        query = new Query(Criteria.where("tree_id").is(treeId));
        TreeDO treeDO = mongoTemplate.findOne(query, TreeDO.class);
        if (treeDO == null) {
            throw new ServiceException(ErrorCodeEnum.E006.code(), "树木信息不存在");
        }
        UserTreeDO userTreeDO = new UserTreeDO();
        userTreeDO.setUserId(userId);
        userTreeDO.setFace(userDO.getFace());
        userTreeDO.setNickname(userDO.getNickname());
        userTreeDO.setTreeId(IdGen.uuid());
        userTreeDO.setTreeName(treeDO.getTreeName());
        userTreeDO.setTreeIcon(treeDO.getTreeIcon());
        userTreeDO.setTreeDesc(treeDO.getTreeDesc());
        userTreeDO.setTreeImage(treeDO.getTreeImage());
        userTreeDO.setGrowValue(treeDO.getGrowValue());
        userTreeDO.setPowerValue(treeDO.getPowerValue());
        userTreeDO.setRewardValue(treeDO.getRewardValue());
        userTreeDO.setCurrentValue(new Double(0));
        userTreeDO.setTreeStatus(0);
        userTreeDO.setWormNum(0);
        userTreeDO.setWormTime(new Long(0));
        Date date = new Date();
        userTreeDO.setGmtCreate(date.getTime());
        userTreeDO.setGmtModified(date.getTime());
        mongoTemplate.insert(userTreeDO);
        //更新用户表树信息
        userManager.upDateAfterChooseTree(userId, userTreeDO.getTreeId());
        return;
    }

    /**
     * 减少树上虫子的数量
     */
    @Override
    public void subWormNum(String userId, String treeId) {
        UserTreeVO treeInfo = getTreeInfoById(userId, treeId);
        if (treeInfo == null) {
            throw new ServiceException(ErrorCodeEnum.E006.code(), "树木信息不存在");
        }
        if (treeInfo.getWormNum() > 0) {
            Query query = new Query(Criteria.where("user_id").is(userId).and("tree_id").is(treeId));
            Update update = new Update();
            update.set("worm_num", treeInfo.getWormNum() - 1);
            mongoTemplate.updateFirst(query, update, UserTreeDO.class);
        }
    }

    /**
     * 减少或保留虫子减少的成长值
     *
     * @param userId
     * @param treeId
     * @param type
     */
    @Override
    public void changePestStatus(String userId, String treeId, String type) {
        Query query = new Query(Criteria.where("user_id").is(userId).and("tree_id").is(treeId));
        UserTreeDO userTreeDO = mongoTemplate.findOne(query, UserTreeDO.class);
        if (userTreeDO == null) {
            throw new ServiceException(ErrorCodeEnum.E300.code(), "暂无树木信息");
        }
        if ("sub".equals(type)) {
            //减少成长值
            subValue(userId, treeId);
            Update update = new Update();
            update.set("sub_value", null);
            mongoTemplate.updateFirst(query, update, UserTreeDO.class);
        } else if ("keep".equals(type)) {
            //保留成长值 减少的值变为0
            Update update = new Update();
            update.set("sub_value", null);
            mongoTemplate.updateFirst(query, update, UserTreeDO.class);
        }
    }
}
